#include "Job.h"
#include "ThreadsPool.h"

#define max(i, j) ((i >= j) ? i : j)

/* this is temporary solution for storing and sorting the results */
vector< vector<Job*> >  *myDoneJobs;

Job::Job(uint _type, uint _inputFileIndx, uint _seqInFile, DiagStretch *_diags) :
	type(_type),
	done(false),
	inputFileIndx(_inputFileIndx),
	seqInFile(_seqInFile),
	matches(),
	diags(_diags)
{
}

Job::~Job()
{
	delete diags;
}

void Job::process()
///task* Job::execute()
{
	switch (type)
	{
				case DIAGS_JOB	:
					processDiags();
					break;
				case FILE_READ:
					readFile();
					break;
				case RESULT_SORT:
					sortJobs();
					break;
				default:
					/* Error - should not reach here */
					cout << "ERROR!!!!!!!!!" << endl;
					break;
	}
	///return NULL;
}

void Job::processDiags()
{
	if (done)
		return;
	InputSequence seq = inSeqsSeq[inputFileIndx].getSequence(seqInFile);
	/* Process all diagonals in the i'th diagonal stretch */
	for (uint k = diags->first; k <= diags->last; k++)
	{
		size_t refInd = 0, inseqInd = 0;
		size_t limit, runner;
		if (diags->isRefSeqIndx) 
		{
			refInd = runner = k;
			limit = refSeq->getLength();
		}
		else
		{
			inseqInd = runner = k;
			limit = seq.getLength();

		}

		size_t currSeq = 0;
		size_t sRef = refInd+1;
		size_t sInseq =  inseqInd+1;
		while (runner < limit)
		{
			if (refSeq->getBit(seq.getCharAsShort(inseqInd), refInd) == 1)
			{
				currSeq++;
			}
			else /* current sequence ended */
			{
				if (currSeq >= minMatchLength)
					matches.push_back(Match(sRef, refInd, sInseq, inseqInd));

				/* +1 for the indexing vs counting gap 
				   +1 as the match will be in the next index, it any */
				sRef = refInd+2;
				sInseq =  inseqInd+2;
				currSeq = 0;
			}
			refInd++;
			inseqInd++;
			runner++;
		}
		/* in case current diagonal ended with a sequence */
		if (currSeq >= minMatchLength)
			matches.push_back(Match(sRef, refInd, sInseq, inseqInd));
	}

	done = true;
}

void Job::readFile()
{
	while (!inSeqsSeq[inputFileIndx].doneReading())
	{
		inSeqsSeq[inputFileIndx].addOneSequence();
		
		/* create jobs to process the sequence */
		
		/* add Jobs with diagonals according to ref string (end to begining) */
		int temp1 = refSeq->getLength() - minMatchLength - JOB_SIZE;
		int temp2 = refSeq->getLength() - minMatchLength;
		int currStartDiag = max(0, temp1); /* ???????????????????? WHY? WHY? WHY? */
		int currEndDiag = max(0, temp2);
		while (currStartDiag < currEndDiag)
		{
			Job *newJob = new Job(DIAGS_JOB, inputFileIndx, inSeqsSeq[inputFileIndx].getSequencesNum()-1, new DiagStretch(true, currStartDiag, currEndDiag));
			pool->addJob(newJob);
///			tbb::task::enqueue(*new() Job(DIAGS_JOB, inputFileIndx, inSeqsSeq[inputFileIndx].getSequencesNum() - 1, new DiagStretch(true, currStartDiag, currEndDiag)));
			
#ifdef	DEBUG
			cout << "Added ref string diagonal: " << currStartDiag << " to " << currEndDiag << endl;
#endif	/* DEBUG */
			
			temp1 = currStartDiag-1;
			temp2 = currStartDiag-JOB_SIZE;
			currEndDiag = max(0, temp1);
			currStartDiag = max(0, temp2);
		}
		
		/* add Jobs with diagonals according to input string (begining to end) */
		temp1 = inSeqsSeq[inputFileIndx].getLastSequence().getLength() - minMatchLength - JOB_SIZE;
		temp2 = inSeqsSeq[inputFileIndx].getLastSequence().getLength() - minMatchLength;
		currStartDiag = max(1, temp1);
		currEndDiag = max(1, temp2);
		while (currStartDiag < currEndDiag)
		{
			Job *newJob = new Job(DIAGS_JOB, inputFileIndx, inSeqsSeq[inputFileIndx].getSequencesNum()-1, new DiagStretch(false, currStartDiag, currEndDiag));
			pool->addJob(newJob);
			
#ifdef	DEBUG
			cout << "Added input string diagonal: " << currStartDiag << " to " << currEndDiag << endl;
#endif	/* DEBUG */
			
			temp1 = currStartDiag-1;
			temp2 = currStartDiag-JOB_SIZE;
			currEndDiag = max(1, temp1);
			currStartDiag = max(1, temp2);
		}
	}
}
	
void Job::sortJobs()
{}
